package com.tanhua.dubbo.server.api;

import com.alibaba.dubbo.common.utils.CollectionUtils;
import com.alibaba.dubbo.config.annotation.Service;
import com.mongodb.client.result.DeleteResult;
import com.tanhua.dubbo.server.pojo.*;
import com.tanhua.dubbo.server.vo.PageInfo;
import lombok.extern.slf4j.Slf4j;
import org.bson.types.ObjectId;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Sort;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.stereotype.Component;

import java.util.*;
import java.util.stream.Collectors;

/**
 * @Author: cloudy
 * @Description:
 * @Date: Created in 17:11 2021/1/6
 * @ModifiedBy:
 */
@Service(version = "1.0.0")
@Slf4j
public class QuanZiApiImpl implements QuanZiApi {

    @Autowired
    private MongoTemplate mongoTemplate;

    @Autowired
    private IdService idService;

    /**
     * 发布朋友圈
     *
     * @param publish
     * @return
     */
    @Override
    public String savePublish(Publish publish) {
        //对publish进行校验
        if (publish == null) {
            return null;
        }

        try {
            //先补全publish信息,之后保存到发布表中
            publish.setId(ObjectId.get());

            //用于推荐引擎使用
            publish.setPid(this.idService.createId("publish", publish.getId().toHexString()));

            publish.setCreated(System.currentTimeMillis());
            publish.setSeeType(1); //查看权限
            this.mongoTemplate.save(publish);

            //创建相册对象,将其存到MongoDB中相册表里
            Album album = new Album();
            album.setId(ObjectId.get());
            album.setCreated(System.currentTimeMillis());
            album.setPublishId(publish.getId());
            this.mongoTemplate.save(album, "quanzi_album_" + publish.getUserId());

            //从MongoDB中查询发布者的好友集合,遍历存储到他们各自的时间线表中
            Query query = Query.query(Criteria.where("userId").is(publish.getUserId()));
            List<Users> users = this.mongoTemplate.find(query, Users.class);

            for (Users user : users) {
                TimeLine timeLine = new TimeLine();
                timeLine.setId(ObjectId.get());
                timeLine.setDate(System.currentTimeMillis());
                timeLine.setUserId(user.getUserId());
                timeLine.setPublishId(publish.getId());

                this.mongoTemplate.save(timeLine, "quanzi_time_line_" + user.getFriendId());
            }
            return publish.getId().toHexString();
        } catch (Exception e) {
            log.error("发布圈子出错", e);
        }
        return null;
    }

    /**
     * 查询动态
     *
     * @param userId
     * @param page
     * @param pageSize
     * @return
     */
    @Override
    public PageInfo<Publish> queryPublishList(Long userId, Integer page, Integer pageSize) {
        //通过MongoDB去查询,当前用户的时间线表
        PageRequest pageRequest = PageRequest.of(page - 1, pageSize, Sort.by(Sort.Order.desc("date")));
        Query query = new Query().with(pageRequest);

        String collectionName = "quanzi_time_line_" + userId;
        if (userId == null) {
            collectionName = "quanzi_time_line_recommend";
        }

        List<TimeLine> timeLineList = this.mongoTemplate.find(query, TimeLine.class, collectionName);

        //查询完时间线表,将其中的publishId搞成一个集合
        List<ObjectId> publishIdList = new ArrayList<>();
        for (TimeLine timeLine : timeLineList) {
            publishIdList.add(timeLine.getPublishId());
        }

        //通过id集合查询publish表当中的信息,并放到一个集合里
        Query queryPublish = Query.query(Criteria.where("id").in(publishIdList)).with(Sort.by(Sort.Order.desc("created")));
        List<Publish> publishList = this.mongoTemplate.find(queryPublish, Publish.class);

        //创建一个PageInfo对象,对它进行赋值并返回
        PageInfo<Publish> pageInfo = new PageInfo<>();
        pageInfo.setPageNum(page);
        pageInfo.setPageSize(pageSize);
        pageInfo.setRecords(publishList);
        pageInfo.setTotal(0); //不提供总数
        return pageInfo;
    }

    /**
     * 点赞
     *
     * @param userId
     * @param publishId
     */
    @Override
    public boolean saveLikeComment(Long userId, String publishId) {
        //对是否已经点赞进行判断,可以通过MongoDB查询
        Query query = Query.query(Criteria.where("userId").is(userId).and("publishId").is(new ObjectId(publishId)).and("commentType").is(1));
        long count = this.mongoTemplate.count(query, Comment.class);
        if (count > 0) {
            return false;
        }
        return this.saveComment(userId, publishId, 1, null);
    }

    /**
     * 取消点赞、喜欢等
     *
     * @return
     */
    @Override
    public boolean removeComment(Long userId, String publishId, Integer commentType) {
        Query query = Query.query(Criteria
                .where("publishId").is(new ObjectId(publishId))
                .and("userId").is(userId)
                .and("commentType").is(commentType));
        DeleteResult remove = this.mongoTemplate.remove(query, Comment.class);

        return remove.getDeletedCount() > 0;
    }

    /**
     * 喜欢
     *
     * @param userId
     * @param publishId
     */
    @Override
    public boolean saveLoveComment(Long userId, String publishId) {
        //对是否已经点赞进行判断,可以通过MongoDB查询
        Query query = Query.query(Criteria.where("userId").is(userId).and("publishId").is(new ObjectId(publishId)).and("commentType").is(3));
        long count = this.mongoTemplate.count(query, Comment.class);
        if (count > 0) {
            return false;
        }
        return this.saveComment(userId, publishId, 3, null);
    }

    /**
     * 保存评论
     *
     * @param userId
     * @param publishId
     * @param type
     * @return
     */
    @Override
    public boolean saveComment(Long userId, String publishId, Integer type, String content) {
        try {
            Comment comment = new Comment();
            comment.setId(ObjectId.get());
            comment.setPublishId(new ObjectId(publishId));
            comment.setUserId(userId);
            comment.setContent(content);
            comment.setCommentType(type);
            comment.setCreated(System.currentTimeMillis());

            //保存发布者的用户id
            Publish publish = this.mongoTemplate.findById(comment.getPublishId(), Publish.class);
            if (null != publish) {
                comment.setPublishUserId(publish.getUserId());
            } else {
                Video video = this.mongoTemplate.findById(comment.getPublishId(), Video.class);
                if (null != video) {
                    comment.setPublishUserId(video.getUserId());
                }
            }

            this.mongoTemplate.save(comment);
            return true;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return false;
    }

    @Override
    public Long queryCommentCount(String publishId, Integer type) {
        Query query = Query.query(Criteria.where("publishId").is(new ObjectId(publishId)).and("commentType").is(type));
        return this.mongoTemplate.count(query, Comment.class);
    }

    @Override
    public Publish queryPublishById(String id) {
        return this.mongoTemplate.findById(id, Publish.class);
    }

    @Override
    public PageInfo<Comment> queryCommentList(String movementId, Integer page, Integer pageSize) {
        PageRequest pageRequest = PageRequest.of(page - 1, pageSize, Sort.by(Sort.Order.asc("created")));
        Query query = Query.query(Criteria.where("publishId").is(new ObjectId(movementId)).and("commentType").is(2)).with(pageRequest);
        List<Comment> comments = this.mongoTemplate.find(query, Comment.class);

        PageInfo<Comment> pageInfo = new PageInfo<>();
        pageInfo.setTotal(0);
        pageInfo.setPageNum(page);
        pageInfo.setPageSize(pageSize);
        pageInfo.setRecords(comments);

        return pageInfo;
    }

    @Override
    public PageInfo<Comment> queryCommentListByUser(Long userId, Integer type, Integer page, Integer pageSize) {

        PageRequest pageRequest = PageRequest.of(page - 1, pageSize, Sort.by(Sort.Order.desc("created")));
        Query query = Query.query(Criteria.where("publishUserId").is(userId)
                .and("commentType").is(type)).with(pageRequest);

        List<Comment> commentList = this.mongoTemplate.find(query, Comment.class);

        PageInfo<Comment> pageInfo = new PageInfo<>();
        pageInfo.setPageNum(page);
        pageInfo.setPageSize(pageSize);
        pageInfo.setRecords(commentList);
        pageInfo.setTotal(0); //不提供总数
        return pageInfo;
    }

    @Override
    public List<Publish> queryPublishByPids(List<Long> pids) {
        Query query = Query.query(Criteria.where("pid").in(pids));
        return this.mongoTemplate.find(query, Publish.class);
    }

    /***
     *
     * @param userId 你要查看的用户相册的用户id
     * @param page
     * @param pageSize
     * @return
     */
    @Override
    public PageInfo<Publish> queryAlbumList(Long userId, Integer page, Integer pageSize) {
        PageInfo<Publish> pageInfo = new PageInfo<>();
        pageInfo.setPageNum(page);
        pageInfo.setPageSize(pageSize);
        pageInfo.setTotal(0); //不提供总数
        PageRequest pageRequest = PageRequest.of(page - 1, pageSize - 1, Sort.by(Sort.Order.desc("created")));
        Query query = new Query().with(pageRequest);
        List<Album> albumList = this.mongoTemplate.find(query, Album.class, "quanzi_album_" + userId);

        if (CollectionUtils.isEmpty(albumList)) {
            return pageInfo;
        }

        List<ObjectId> publishIdList = albumList.stream().map(Album::getPublishId).collect(Collectors.toList());


        Query queryPublish = Query.query(Criteria.where("id").in(publishIdList)).with(Sort.by(Sort.Order.desc("created")));
        List<Publish> publishList = this.mongoTemplate.find(queryPublish, Publish.class);
        pageInfo.setRecords(publishList);

        return pageInfo;
    }

    /**
     * 活跃数
     * @param thisYearTimeList
     * @param lastYearTimeList
     * @return
     */
    @Override
    public List<Integer> queryCommentCounts(List<Long> thisYearTimeList, List<Long> lastYearTimeList) {
        List<Integer> userIdList=new ArrayList<>();
        for (int i = 0; i < thisYearTimeList.size()-1; i++) {
            Set<Long> thisYearByTime = getActiveByTime(thisYearTimeList.get(i), thisYearTimeList.get(i + 1));
            Set<Long> lastYearByTime = getActiveByTime(lastYearTimeList.get(i), lastYearTimeList.get(i + 1));
            userIdList.add(thisYearByTime.size());
            userIdList.add(lastYearByTime.size());
        }
        return userIdList;
    }

    /**
     * 获取活跃数
     * @param startDate
     * @param endDate
     * @return
     */
    public Set<Long> getActiveByTime(Long startDate, Long endDate){
        Criteria startCriteria = Criteria.where("created").gte(startDate);
        Criteria endCriteria = Criteria.where("created").lt(endDate);
        Criteria criteria = new Criteria().andOperator(startCriteria, endCriteria);

        Query query = Query.query(criteria);
        List<Log> logList = this.mongoTemplate.find(query, Log.class);
        Set<Long> userIds = new HashSet<>();
        for (Log log1 : logList) {
            userIds.add(log1.getUserId());
        }
        return userIds;
    }

    @Override
    public List<Integer> queryNextDay(List<List<Long>> nextList, List<Long> thisYearTimeList, List<Long> lastYearTimeList) {

        List<Integer> loginCounts = new ArrayList<>();
        // createdIdList里 是对应时间段的前一天新建用户的id
        for (int i = 0; i < thisYearTimeList.size() - 1; i += 2) {
            // 在此时间段登录的 并且是对应时间段id里的 是算作次日留存的用户
            Criteria thisStartCriteria = Criteria.where("created").gte(thisYearTimeList.get(i));
            Criteria thisEndCriteria = Criteria.where("created").lt(thisYearTimeList.get(i + 1));
            Criteria thisCriteria =  Criteria.where("userId").in(nextList.get(i)).andOperator(thisStartCriteria, thisEndCriteria);

            Criteria lastStartCriteria = Criteria.where("created").gte(thisYearTimeList.get(i));
            Criteria lastEndCriteria = Criteria.where("created").lt(thisYearTimeList.get(i + 1));
            Criteria lastCriteria = Criteria.where("userId").in(nextList.get(i + 1)).andOperator(lastStartCriteria, lastEndCriteria);

            Query thisYearQuery = Query.query(thisCriteria);
            Query lastYearQuery = Query.query(lastCriteria);

            long thisYearCount = this.mongoTemplate.count(thisYearQuery, UserLogin.class);
            long lastYearCount = this.mongoTemplate.count(lastYearQuery, UserLogin.class);
            // 先存今年 后存去年(索引偶数为今年, 奇数为去年)
            loginCounts.add((int) thisYearCount);
            loginCounts.add((int) lastYearCount);
        }
        return loginCounts;
    }
}